package ner;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import forum.ForumFactory;
import forum.ForumItem;
import forum.ForumPost;
import forum.ForumSentence;
import parser.ParserAnnotation;
import parser.StanfordAnnotation;

public class StanfordNER extends NER {
	public StanfordNER(ForumFactory fac) {
		super(fac);
	}

	// Filter MONEY, NUMBER, ORDINAL, TIME, DATE

	@Override
	public void items(ForumPost fp) {
		ParserAnnotation pa = fp.getParserAnnotation();
		if (!(pa instanceof StanfordAnnotation))
			throw new Error("stanford or regexp NER requires stanford parser.");

		StanfordAnnotation sa = (StanfordAnnotation) pa;

		for (int i = 0; i < sa.getNbrSentences(); i++) {
			ForumSentence fs = fp.getSentences().get(i);
			String text = sa.getSentences().get(i);
			List<String> ners = sa.getNER(i);
			List<Integer> indexes = sa.getTokenIndexes(i);
			if (ners.isEmpty()) {
				fs.setItems(new ForumItem[]{fac.makeItem("NOITEM", "NOTOPIC")});
				continue;
			}
			List<ForumItem> items = new ArrayList<ForumItem>();
			ListIterator<String> itr = ners.listIterator();
			String annotatedSent = "<p class=\"post-" + fs.getEmotion() + "\">";
			int prevEnd = 0; // whitespace is sometimes included, sometimes not.
			while (itr.hasNext()) {
				int tokenStart = itr.nextIndex();
				String iStr = makeItem(itr, ners);
				int tokenEnd = itr.nextIndex();
				int start = indexes.get(tokenStart * 2);
				int end = indexes.get(tokenEnd * 2 - 1);
				if (start != prevEnd)
					start = start - 1;
				prevEnd = end;
				if (iStr != null) {
					String item = iStr.split("/")[0];
					String topic = iStr.split("/")[1];
					if (item.equals("-TEMP-")) {
						item = text.substring(start, end);
						if (item.startsWith(" "))
							item = item.substring(1);
					}
					ForumItem fi = fac.makeItem(item, topic);
					if (!items.contains(fi))
						items.add(fi);
					annotatedSent += "<acronym title=\"" + fi.getItemName()
							+ "\"><span class=\"emotion-" + fs.getEmotion()
							+ "\">" + text.substring(start, end)
							+ "</span></acronym>";
				} else
					annotatedSent += text.substring(start, end);
			}
			annotatedSent += "</p>";
			fs.setItemsText(annotatedSent);
			if (items.isEmpty())
				fs.setItems(new ForumItem[]{fac.makeItem("NOITEM", "NOTOPIC")});
			else
				fs.setItems(items.toArray(new ForumItem[items.size()]));
		}
	}

	// This is a mess to avoid adding explicitly all the combinations of
	// typing a QV release in the ner regexp-file. That would be thousands of
	// extra lines.
	private String makeItem(ListIterator<String> itr, List<String> list) {
		String ner = eatDuplicates(itr);

		if (ner.equals("O") || ner.equals(""))
			return null;

		String item;
		String topic;
		String[] itemTopic = ner.split("/");
		if (itemTopic.length == 1) {
			topic = itemTopic[0];
			item = "-TEMP-";
		} else {
			item = itemTopic[0];
			topic = itemTopic[1];
		}

		if (complexMiddle(ner)) {
			itr.previous();
			return concatVars(itr);
		} else {
			if (topic.equals("MONEY") || topic.equals("NUMBER")
					|| topic.equals("ORDINAL") || topic.equals("TIME")
					|| topic.equals("DATE"))
				return null;
			return item + "/" + topic;
		}
	}

	private String concatVars(ListIterator<String> itr) {
		String relType = ""; // Ex: RC 2 or IR
		String version = ""; // Ex: QlikView 10
		String weakVersion = ""; // Ex: 9
		boolean qvMatch = false;

		// Remove starting stop words, parenthesis and so on
		if (itr.next().endsWith("VARXTRA"))
			return null;
		else
			itr.previous();

		do {
			String vars = eatDuplicates(itr);
			String[] var = vars.split("/");
			String item = var[0];
			String topic = var.length == 1 ? var[0] : var[1];

			if (vars.equals("O") || !complexMiddle(vars))
				break;

			if (topic.equals("QVVERSION"))
				version = item;
			else if (topic.equals("VARQVVERSION"))
				weakVersion = item;
			else if (topic.equals("QVREL"))
				relType = item;
			else if (topic.equals("QVMISC") && item.equals("QV"))
				qvMatch = true;
		} while (itr.hasNext()
				&& !((!version.isEmpty() || !weakVersion.isEmpty()) && !relType
						.isEmpty()));

		// Backtrack non-complex
		String prev;
		do {
			prev = itr.previous();
		} while (!complex(prev));
		itr.next();

		// Create item and topic
		String item = "";
		String topic = "";
		if (!relType.isEmpty() || !version.isEmpty()
				|| (qvMatch && !weakVersion.isEmpty())) {
			item = (version.isEmpty() ? weakVersion : version) + relType;
			if (!item.startsWith("QV"))
				item = "QV" + item;
			topic = "QVREL";
			return item + "/" + topic;
		} else if (qvMatch)
			return "QV/QVMISC";
		else
			return null;
	}

	private String eatDuplicates(ListIterator<String> itr) {
		String prevNer;
		String ner = "";
		do {
			prevNer = ner;
			ner = itr.next();
		} while ((prevNer.isEmpty() || ner.equals(prevNer)) && itr.hasNext());
		if (prevNer.isEmpty())
			return ner;
		if (!prevNer.equals(ner))
			itr.previous();
		return prevNer;
	}

	private boolean complex(String str) {
		String[] var = str.split("/");
		String item = var[0];
		String topic = var.length == 1 ? var[0] : var[1];
		return topic.equals("VARQVVERSION") || topic.equals("QVVERSION")
				|| topic.equals("QVREL")
				|| (topic.equals("QVMISC") && item.equals("QV"));
	}

	private boolean complexMiddle(String str) {
		String[] var = str.split("/");
		String item = var[0];
		String topic = var.length == 1 ? var[0] : var[1];
		return topic.startsWith("VAR") || topic.equals("QVVERSION")
				|| topic.equals("QVREL")
				|| (topic.equals("QVMISC") && item.equals("QV"));
	}
}
